﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Xml;
using System.Web.Mvc;
using System.Web;
using System.Text.RegularExpressions;

namespace WisPortal
{

    public enum NotificationType
    {
        Information,
        Alert,
        Error
    }

    /// <summary>
    /// AppUIParser is a class to parse specific format in AppUI.xml
    /// </summary>
    /// <remarks></remarks>
    public class AppUIParser
    {
        private ControllerContext viewContext;
        private ViewDataDictionary viewData;

        public AppUIParser(ControllerContext vContext, ViewDataDictionary vData)
        {
            viewContext = vContext;
            viewData = vData;           
        }

        public bool IsDialog()
        {
            return viewData["isDialog"] != null && (bool)viewData["isDialog"];
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sb"></param>
        /// <param name="config"></param>
        public void RenderNav(StringBuilder sb, XmlNode config)
        {
            //<nav>
            //            
            //                <ul>
            //                    <li>
            //                        <a href="#"><i class="icon-home"></i></a>
            //                    </li>
            //                    <li>
            //                        <a href="#">Sports & Toys</a>
            //                    </li>
            //                    <li>
            //                        <a href="#">Toys & Hobbies</a>
            //                    </li>
            //                    <li>
            //                        <a href="#">Learning & Educational</a>
            //                    </li>
            //                    <li>
            //                        <a href="#">Astronomy & Telescopes</a>
            //                    </li>
            //                    <li>
            //                        Telescope 3735SX 
            //                    </li>
            //                </ul>
            //            </div>
            //        </nav>

            sb.AppendLine("<nav>\r\n<div id=\"jCrumbs\" class=\"breadCrumb module\">\r\n<ul>");

            sb.AppendLine("</ul>\r\n</div>\r\n</nav>");

        }

        /// <summary>
        /// Render the buttons right to the title area
        /// </summary>
        /// <param name="sb"></param>
        /// <param name="config"></param>
        public void RenderTools(StringBuilder sb,XmlNode config)
        {
            XmlNodeList toolNodes = config.SelectNodes(".//Tools/Tool");
            if (toolNodes.Count == 0) return;
            sb.AppendLine("<div class=\"btn-toolbar pull-right\">");
            foreach (XmlNode toolNode in toolNodes)
            {
                RenderTool(sb, toolNode);
            }
            sb.AppendLine("</div>");
        }

        public void RenderTool(StringBuilder sb, XmlNode node)
        {
            StringBuilder sbAttr = new StringBuilder();
            string href = ParseCommand(null, node);
            sbAttr.Append(XmlHelper.InsertAttributeWhenEmpty(node, "id", " id=\"{0}\""));
            sbAttr.Append(XmlHelper.InsertAttributeWhenEmpty(node, "rev", " rev=\"{0}\""));
            sbAttr.Append(XmlHelper.InsertAttributeWhenEmpty(node, "class", " class=\"{0}\""));
            
            string text = XmlHelper.GetAttributeValue(node, "text");
            string title = XmlHelper.GetAttributeValue(node, "title");
            string dialog = XmlHelper.GetAttributeValue(node, "dialog","false");
            
            if (text.Length == 0 && title.Length > 0)
                text = title;
            if (title.Length == 0 && text.Length > 0)
                title = text;

            sb.AppendFormat("<a {3} href=\"{0}\" {4} title=\"{2}\">{1}</a>",
                href,
                UI.Localize(text),
                UI.Localize(title),
                sbAttr.ToString(),
                dialog.Equals("true") ? "data-toggle=\"modal\" data-target=\"#modal-dialog\"" : ""); // id\rev\class
        }

        /// <summary>
        /// Render Tool or Action
        /// </summary>
        /// <param name="sb"></param>
        /// <param name="node"></param>
        public void RenderAction(DataRow row, StringBuilder sb, XmlNode node)
        {
            StringBuilder sbAttr = new StringBuilder();
            string rev = XmlHelper.GetAttributeValue(node, "rev");
            string href = ParseCommand(row, node);
            if (rev.Length > 0)
            {
                sb.AppendFormat("<div class=\"hidden\" title=\"{0}\" id=\"{1}\"></div>\n",
                       UI.Localize(XmlHelper.GetAttributeValue(node, "dialog_title", "New Item")),
                       XmlHelper.GetAttributeValue(node, "rev"));
                //Add rev to the foot parameters
                href += "&rev=" + rev;            
            }

            string id = XmlHelper.GetAttributeValue(node, "id");

            sbAttr.Append(XmlHelper.InsertAttributeWhenEmpty(node, "aclass", " class=\"{0}\""));
            sbAttr.Append(XmlHelper.InsertAttributeWhenEmpty(node, "rev", " data-toggle=\"modal\" data-backdrop=\"static\" data-target=\"#dlg_{0}\""));
            
            string text = XmlHelper.GetAttributeValue(node,"text");
            string title = XmlHelper.GetAttributeValue(node, "title");

            if (text.Length == 0 && title.Length > 0)
                text = title;
            if (title.Length == 0 && text.Length > 0)
                title = text;

            sb.AppendFormat("<span class=\"{0}\"><a id=\"{5}\" {4} href=\"{1}\" title=\"{3}\">{2}</a></span>",
                XmlHelper.GetAttributeValue(node, "class"),
                href,
                UI.Localize(text),
                UI.Localize(title),
                sbAttr.ToString(),
                id); // id\rev\class
        }
        /// <summary>
        /// Render the hyper links under Title area
        /// </summary>
        /// <param name="sb"></param>
        /// <param name="config"></param>
        public void RenderExtraTools(StringBuilder sb,XmlNode config)
        {
            sb.AppendLine("<div class=\"extra-tools clearfix\">");
            ////
            sb.AppendLine("</div>");
        }

        /// <summary>
        /// Parse the param sytax
        /// </summary>
        /// <param name="idFormat"></param>
        /// <returns></returns>
        protected string ParseParam(DataRow row,string idFormat)
        {
            if (idFormat.IndexOf("=") < 0) return idFormat;

            string pName = idFormat.Split("=".ToCharArray())[0];
            string pValueFormat = idFormat.Split("=".ToCharArray())[1].Trim().ToLower().Replace("\"","");

            //Convert into a command format
            pValueFormat = string.Format("{{0}}",pValueFormat);
            string value = GetValueFromFormat(row,pValueFormat);
            if (value == string.Empty)
                return "";
            else
                return string.Format("{0}={1}",pName,value);
        }

        /// <summary>
        /// Get value from value express
        /// </summary>
        /// <param name="row"></param>
        /// <param name="format"></param>
        /// <returns></returns>
        public string GetValueFromFormat(DataRow row,string format)
        {
            string pValueFormat = format.Trim().ToLower().Replace("\"","");
            if(pValueFormat.StartsWith("{") && pValueFormat.EndsWith("}"))
            {
                //Remove the {} characters
                pValueFormat = pValueFormat.Trim("{}".ToCharArray());
                Regex regViewData = new Regex("viewdata\\[(?<key>\\w+)\\]");
                Regex requestData = new Regex("request\\[(?<key>\\w+)\\]");
                Regex rowData = new Regex("row\\[(?<key>\\w+)\\]");
                Regex nowFunc = new Regex("now");

                string key = string.Empty;
                string value = string.Empty;
                if (regViewData.IsMatch(pValueFormat))
                {
                    //Retrieve form view data
                    key = regViewData.Match(pValueFormat).Groups["key"].Value;                
                    value = viewData[key] != null ? viewData[key].ToString() : string.Empty;
                }
                else if (requestData.IsMatch(pValueFormat))
                {
                    //Retrieve from request
                    key = requestData.Match(pValueFormat).Groups["key"].Value;
                    value = viewContext.HttpContext.Request[key] != null ? viewContext.HttpContext.Request[key] : string.Empty;
                }
                else if (rowData.IsMatch(pValueFormat))
                {
                    //Retrieve from dataRow
                    key = rowData.Match(pValueFormat).Groups["key"].Value;
                    value = row != null && row[key] != null ? row[key].ToString() : string.Empty;
                }
                else if (nowFunc.IsMatch(pValueFormat))
                {
                    //Retrieve from datetime
                    //key = nowFunc.Match(pValueFormat).Groups["key"].Value;
                    value = DateTime.Now.ToString();
                }
                else
                {
                    value = pValueFormat;
                }
                return value;
            }
            else
                //Return original value
                return pValueFormat;
        }

        /// <summary>
        /// Parse href format attribute
        /// </summary>
        /// <example>
        /// AppUI.xml Example
        /// View:{view:guid:bizdata_form}
        /// view is the command name; guid is the row id field name; bizdata_form is the unique form name property.
        /// Edit:{edit:guid:bizdata_form}
        /// Delete:{delete:guid}
        /// </example>
        /// <param name="row"></param>
        /// <param name="config"></param>
        /// <returns></returns>
        public string ParseCommand(DataRow row, XmlNode config)
        {
            string cmd = XmlHelper.GetAttributeValue(config, "href").Trim().ToLower();
            //A command must be wrapped with '{}'
            if (cmd.StartsWith("{") && cmd.EndsWith("}") && cmd.Length > 2)
            {
                //Remove {}
                string[] commands = cmd.Substring(1, cmd.Length - 2).Split(":".ToCharArray());
                if (commands.Length > 0)
                {
                    string cmdUrl = viewContext.HttpContext.Request.ApplicationPath +
                            string.Format("data/{0}?{1}=", commands[0], Const.DefaultConfigKey) +
                            viewContext.HttpContext.Request[Const.DefaultConfigKey];
                    cmd = CreateUrl(row, config, cmd, commands, cmdUrl);
                }
            }
            return cmd;
        }


        /// <summary>
        /// Create a url with commands
        /// </summary>
        /// <param name="row"></param>
        /// <param name="config"></param>
        /// <param name="href"></param>
        /// <param name="commands"></param>
        /// <param name="cmdUrl"></param>
        /// <returns></returns>
        private string CreateUrl(DataRow row, XmlNode config, string href, string[] commands, string cmdUrl)
        {
            if (commands.Length <2 || commands.Length > 3)
                throw new CustomerException("Url command must has wrong parameters:" + href);
            
            string formname = commands[1];

            if (formname.IndexOf("/") > -1)
            {
                href = cmdUrl + "&form=" + formname;
            }
            else
            {
                XmlNode formNode = FindFormNodeByName(config, formname);
                if(formNode != null)
                    href = cmdUrl + "&formid=" + XmlHelper.GetAttributeValue(formNode, "guid");
            }

            if (commands.Length == 3)
            {
                string idfiled = ParseParam(row, commands[2]);            
                //Edit command may have 2 commands
                if (commands[2].Equals(idfiled))
                {
                    if (row == null || row[idfiled] == null)
                        throw new CustomerException("Url command faild to find the '" + idfiled + "' in a data row");
           
                    href += "&dataid=" + row[idfiled].ToString();
                }
                else
                    href += "&" + idfiled;
            }
            return href;
        }

        private static XmlNode FindFormNodeByName(XmlNode config, string formname)
        {
            //Use the form name to find the form node
            XmlNode formNode = config.SelectSingleNode(string.Format("//Form[@name='{0}']", formname));
            if (formNode == null)
                throw new CustomerException("Faild to find the form configration with name of " + formname);
            return formNode;
        }

        
        /// <summary>
        /// Wrap notification
        /// </summary>
        /// <param name="notification"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public Dictionary<string,AJAXNotification> GetNotificationJson(string notification, NotificationType type)
        {
            AJAXNotification n = new AJAXNotification();
            n.message = notification;
            n.message_state = "I";
            n.title = "Notice";
            n.type = "N";

            Dictionary<string, AJAXNotification> obj = new Dictionary<string, AJAXNotification>();
            obj.Add("notifications", n);
            return obj;
        }


        /// <summary>
        /// Check wheather the node need to render a dialog
        /// </summary>
        /// <param name="action"></param>
        public void RenderDialog(XmlNode node, StringBuilder sb)
        {
            string rev = XmlHelper.GetAttributeValue(node, "rev");
            if (rev.Length > 0)
            {
                if (sb == null) sb = new StringBuilder();            
                if (sb.ToString().IndexOf(string.Format("id=\"{0}\"", rev)) < 0)
                {
                    string title = XmlHelper.GetAttributeValue(node,"dialog_title","Title");
                    string width = XmlHelper.GetAttributeValue(node,"dialog_width","600px");
                    string height = XmlHelper.GetAttributeValue(node, "dialog_height", "400px");
                    sb.Append(CreateDialog(rev,"",width,height));
                }
            }
        }

        public string CreateDialog(string id, string href, string width, string height)
        {
            return CreateDialog(id, href, "Title", "OK", "Close", width, height, true);
        }

        /// <summary>
        /// Create a dialog html string
        /// </summary>
        /// <param name="id"></param>
        /// <param name="href"></param>
        /// <param name="title"></param>
        /// <param name="okTitle"></param>
        /// <param name="closeTitle"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <param name="fade"></param>
        /// <returns></returns>
        public string CreateDialog(string id, string href, string title, string okTitle, string closeTitle, string width, string height, bool fade)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("<!-- Modal {0} -->\n",id);
            sb.AppendFormat("<div id=\"dlg_{0}\" class=\"modal {1}\" tabindex=\"-1\" role=\"dialog\" aria-labelledby=\"{0}_Label\" aria-hidden=\"true\">\n",
                id,
                fade ? "fade" : "");
            sb.AppendLine("<div class=\"modal-header\">\n");
            sb.AppendFormat("<button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-hidden=\"true\">×</button>\n");
            sb.AppendFormat("<h3 id=\"{1}_Label\">{0}</h3>\n</div>", title, id);
            sb.AppendLine("<div class=\"modal-body\">\n</div>");
            sb.AppendLine("<div class=\"modal-footer\">");
            //sb.AppendFormat("<button class=\"btn\" data-dismiss=\"modal\" aria-hidden=\"true\">{0}</button>", closeTitle);
            //sb.AppendFormat("<button class=\"btn btn-primary\">{0}</button>",okTitle);
            sb.AppendLine("</div></div>");
            
            return sb.ToString();
        }
    }
}
